魔法陣言語parserのcode reading
from 2022/10/01
背景takker.icon
魔法陣言語はinajob.github.ioで試せるが、clientで実行する必要がある
serverless functionにできればscrapboxにも埋め込めて便利そう
ということで、parser部分だけ抜き出して再実装しようと試みた
entry point
init()でSVGとラスタイメージを生成している
(function(){/*...*/}).toString()という黒魔術っぽいコードがある
class
RendererSVGhttps://inajob.github.io/mce3/js/render-svg.js
SVGレンダラー
SimpleParserhttps://inajob.github.io/mce3/js/render-base.js
魔法陣言語の描画専用言語のパーサー
Rendererhttps://inajob.github.io/mce3/js/render.js
ラスタレンダラー
MCLhttps://inajob.github.io/mce3/js/mcl.js
魔法陣言語を魔法陣言語の描画専用言語に変換するparsr
gin.jsっていう古のパーサージェネレータに依存しているのを何とかしたいinajob.icon
機械的にmordernizeできるか試してみたけど無理だったtakker.icon
MCLがお目当てのparserっぽいtakker.icon
workerで構文解析している?
じゃあなんでentry pointでもパーサーを使っているんだろう?
どこだろう? 黒魔術っぽいところは単に文字列を作ってるだけですね。inajob.icon
draw()のworker.onmessageのvar out = p.parse(sout);です(var p = new SimpleParser();)takker.icon
魔法陣言語をレンダー用の中間言語(文字列)としてWorkerとやり取りしているようで、受け取った文字列をレンダー言語の構造に変換するのがSimpleParserのようですね(おおむね改行区切りでリストにするだけですが)inajob.icon
WebWorkerのメッセージでArrayを渡せないんだっけ?(忘れた)
https://developer.mozilla.org/ja/docs/Web/API/Worker/postMessage
いけそうにみえるな
かつてはダメだったのかな・・?覚えてないです
データコピーの都合がつかなかったのかな?takker.icon
今のJSなら魔法陣言語の描画専用言語は不要そう
MCLをcode readingする
gin.jsで文法定義されている
$で始まるものは定義済み終端記号
$DECIMAL:数値
$JS_STRING:JSの文字列
[],"",<>で囲まれた文字列が終端記号となる
<>は中身を正規表現として解釈する
:の前で認識した記号は、その後と同名の関数(別途定義)で処理される
PROGRAMから解析を開始する
/[ \r\n]/は適宜無視される
code:js
this.parser = new Gin.Grammar({
Stmnt: /Cmp:cmp | ! ARG:push = Cmp:assign/, // 代入演算、即値
Cmp: / Expr (< Expr:gt | > Expr:lt | == Expr:eq | != Expr:neq)* /, // 比較演算
Expr: / Term (+ Term:add | - Term:sub)* /, // 加減演算
Term: / Fctr (* Fctr:mul | / Fctr:div | % Fctr:mod)* /, // 乗除演算
// 数字、変数、関数、文字列、括弧
Fctr: / $DECIMAL:fpush | Def | Call | $JS_STRING:push | ( Cmp:pushn ) /,
// 変数、関数呼び出しブロック付き
Call: /(ARG:vpush|( Cmp)):callBegin (("(" ARGLIST{0,1} ")":prepareBlock (("{" PROGRAM "}"){0,1}):funcBody) {0,1}):funcCall/,
// 関数定義
Def: /\\:defBegin ("(" ARGLIST{0,1} ")":prepareBlock "{" PROGRAM "}":funcBody):funcDef/,
// プログラム全行
PROGRAM: /((LINE:line (<;>){0,1})*)/,
LINE: /Stmnt COMM/, //ブロック解析
COMM: /<(\/\/^\r\n*|)>/, //コメント
ARGLIST: /Stmnt:arg (',' ARGLIST){0,1}/, // 引数リスト
ARG: /<a-zA-Za-zA-Z0-9*>/, //識別子
},"PROGRAM", new Gin.Parser.RegExp(/ \r\n/));
仕様書も参照したいが、リンク切れなのでコードから文法を推測するしかない
コードから関数定義(Def)の様子がわからない
\(a,b,c){ PROGRAM }と書くみたい?
関数名の定義はしないの?無名関数なのか?
Yes、変数に代入して使いますinajob.icon
あたったtakker.icon
それにFctrにDefが含まれているから、3+\(a,b,c){...}もvalidになってしまう
どう計算するんだろう
これは実行時エラーになりそうinajob.icon
単に文法エラーにしてないだけですね。了解ですtakker.icon
bread-n-butterで実装し直してみる
途中まで書いて挫折
上述した不可解な文法があり、具体的なコードのイメージがつかなかった
やっぱり作例か仕様書がないと、これ以上読み解けない
後で見えるところに置きますねinajob.icon
現時点だとMCE3の、ソースのpreludeが参考になるかも
これか!ありがとうございますtakker.icon
変数宣言・代入に!をつけるのか
やりたくなかったけど、パーサー周りで試行錯誤して、よくわからなかったので妥協した記憶inajob.icon
歴史的経緯takker.icon
リンク切れ解消しました!
ありがとうございます!見れました!takker.icon
15:28:39 字句解析までできた
https://github.com/takker99/magical-circle-engine/commit/839eba8c74917bf35a7beb560079aea19fc8d6e0
はやい!inajob.icon
2024-04-01 13:55:32 実行エンジン完成
https://github.com/takker99/magical-circle-engine/commit/1009da26a20faee733f8be60e3428b013e997cbc
テストはまだしてないので動くかどうかわからない
組み込み関数は未実装